<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1, minimum-scale=1,maximum-scale=1">
  <meta name="description" content="一款超级玛丽的跑酷游戏">
  <title>玛丽酷跑</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/jquery-impromptu/6.2.3/jquery-impromptu.min.css" rel="stylesheet">
  <style>
    * { padding: 0; margin: 0; }

    html {
      height: 100%;
    }
    body {
      min-height: 100%;
    }

    .rank {
      display: flex;
      flex-direction: column;
      padding: 15px;
    }
    .rank-item {
      display: flex;
      width: 100%;
      align-items: center;
      padding: 5px 0;
      font-size: 1.2em;
    }
    .rank-name {
      flex: none;
    }
    .rank-time {
      font-size: 0.4em;
      color: #aeaeae;
    }
    .rank-line {
      flex: 1;
      height: 0;
      overflow: hidden;
      border-top: 1px dashed #000;
      margin: 0 10px;
    }
    .rank-score {
      flex: none;
    }
  </style>
  <script src="parkour.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/leancloud-storage@4.10.1/dist/av-min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery-impromptu/6.2.3/jquery-impromptu.min.js"></script>
  <script>
    var savedUser = localStorage.getItem('user');
    var ranks = [];
    var inputing = false;

    AV.init({
      appId: "Mp8cpIMsHcuDLR8RCsroqlII-9Nh9j0Va",
      appKey: "zXBASj13JavcETYw5triHTJb",
      serverURL: "https://mp8cpims.lc-cn-e1-shared.com"
    });

    function saveScore(score, callbck) {
      if (score > 0) {
        var user = localStorage.getItem('user') || savedUser;
        if (!user) {
          user = '';
          for (var i = 0; i < 10; i++) {
            user += String.fromCharCode(Math.floor(Math.random() * 26) + 'a'.charCodeAt(0));
          }
          inputing = true;
          $.prompt('<input id="user" type="text" value="' + user + '" style="width: 100%; padding: 5px; box-sizing: border-box; border: 1px solid;" />', {
            title: '恭喜你获得' + score + '分,请输入用户名上传结果',
            submit: function(event, value) {
              inputing = false;
              if (value && document.getElementById('user').value) {
                savedUser = document.getElementById('user').value;
                localStorage.setItem('user', savedUser);
                saveScore(score, callbck);
              } else {
                callbck && callbck();
              }
            }
          });
        } else {
          var Score = AV.Object.extend('Score');
          var data = new Score();
          data.set('score', score);
          data.set('user', user);
          data.save().then(function(data) {
            if (!ranks.length || score > ranks[ranks.length - 1].score) {
              refresh();
            }
          });
          savedUser = user;
          localStorage.setItem('user', user);
          callbck && callbck();
        }
      } else {
        callbck && callbck();
      }
    }

    function refresh() {
      var query = new AV.Query('Score');
      query.addDescending('score');
      query.addAscending('createdAt');
      query.limit(50);
      query.find().then(list => {
        for (var i = 0; i < list.length; i++) {
          list[i] = {
            user: list[i].get('user'),
            score: list[i].get('score'),
            createdAt: list[i].get('createdAt')
          }
        }
        // for (var i = 0; i < list.length; i++) {
        //   if (list.slice(0, i).some(data => data.user === list[i].user)) {
        //     list.splice(i, 1);
        //     i--;
        //   }
        // }
        var rank = document.getElementById('rank');
        rank.innerHTML = '';
        for (var i = 0; i < list.length; i++) {
          rank.innerHTML += '<div class="rank-item"><span class="rank-name">' + list[i].user + '<span class="rank-time"> ' + list[i].createdAt.toJSON().replace(/T|Z/ig, ' ').substring(5, 16) + '</span></span><span class="rank-line">&nbsp;</span><span class="rank-score">' + list[i].score + '</span></div>';
        }
        ranks = list;
      })
    }
  </script>
  <script>
    var parkour;
    function initParkour() {
      parkour = new Parkour('parkour', {
        size: {                 //各尺寸配置
          container: {          //容器尺寸
            width: 400,       
            height: 300
          },
          protagonist: {        //主角尺寸
            width: 16,
            height: 32
          },
          awards: [             //奖品尺寸(多种)
            {
              width: 10,
              height: 15
            }
          ],
          background: {         //背景尺寸
            width: 400
          },
          tile: {               //地块尺寸(所有地块的宽度需要一致)
            width: 32           
          },
          tiles: [              //地块尺寸(不同高度的地块的设置)
            {     
              height: 54
            },
            {     
              height: 36
            },
            {     
              height: 72
            },
            {     
              height: 72
            },
            {     
              height: 90
            },
            {     
              height: 18
            }
          ],
          flags: [
            {
              width: 16,
              height: 32
            },
            {
              width: 16,
              height: 16
            },
            {
              width: 16,
              height: 32
            },
            {
              width: 54,
              height: 36
            },
            {
              width: 18,
              height: 18
            },
            {
              width: 54,
              height: 36
            }
          ],
          enemies: [
            {
              width: 18,
              height: 18,
              top: 4,
              left: 2,
              right: 2
            },
            {
              width: 18,
              height: 27,
              top: 12
            },
            {
              width: 18,
              height: 27,
              top: 12,
              left: 1,
              bottom: 1,
              right: 1
            }
          ]
        },
        assets: {               //各资源的配置
          protagonist: {        //主角资源配置
            staying: 'images/protagonist-staying.png',         //
            running: [          //奔跑动作的帧图片
              'images/protagonist-running-1.png',
              'images/protagonist-running-2.png',
              'images/protagonist-running-3.png'
            ],
            jumping: 'images/protagonist-jumping.png',  //跳跃动作的图片
            deading: 'images/protagonist-deading.png',  //死亡坠落的图片
            dead: 'images/protagonist-dead.png'
          },
          backgrounds: [         //背景图,(背景滚动时可以多张首尾衔接)
            'images/background-1.png',
            'images/background-2.png',
            'images/background-3.png',
            'images/background-4.png',
            'images/background-5.png'
          ],
          tiles: [              //地块图片资源
            {
              left: [
                'images/tile-2-left.png'
              ],
              middle: [
                'images/tile-2-middle.png'
              ],
              right: [
                'images/tile-2-right.png'
              ]
            },
            {
              left: [           //左侧地块图片资源(多个时每次随机一个)
                'images/tile-1-left.png'
              ],
              middle: [         //中间地块图片资源(多个时每次随机一个)
                'images/tile-1-middle.png'
              ],
              right: [          //右侧地块图片资源(多个时每次随机一个)
                'images/tile-1-right.png'
              ]
            },
            {
              left: [
                'images/tile-3-left.png'
              ],
              middle: [
                'images/tile-3-middle.png'
              ],
              right: [
                'images/tile-3-right.png'
              ]
            },
            {
              left: [
                'images/tile-4-left.png'
              ],
              middle: [
                'images/tile-4-middle.png'
              ],
              right: [
                'images/tile-4-right.png'
              ]
            },
            {
              left: [
                'images/tile-5-left.png'
              ],
              middle: [
                'images/tile-5-middle.png'
              ],
              right: [
                'images/tile-5-right.png'
              ]
            },
            {
              left: [
                'images/tile-6-left.png'
              ],
              middle: [
                'images/tile-6-middle-0.png',
                'images/tile-6-middle-1.png',
                'images/tile-6-middle-2.png',
                'images/tile-6-middle-3.png'
              ],
              right: [
                'images/tile-6-right.png'
              ]
            }
          ],
          awards: [
            {
              normal: [ 'images/award-1.png' ] //正常状态下的奖品图片
            }
          ],
          flags: [
            [
              'images/flag-1-1.png',
              '',
              'images/flag-1-2.png',
              '',
              'images/flag-1-3.png',
              ''
            ],
            ['images/flag-2.png'],
            ['images/flag-3.png'],
            ['images/flag-4.png'],
            ['images/flag-5.png'],
            ['images/flag-6.png']
          ],
          enemies: [
            {
              running: [
                'images/enemy-1-1.png',
                'images/enemy-1-2.png',
                'images/enemy-1-3.png',
                'images/enemy-1-4.png',
              ],
              dead: 'images/enemy-1-dead.png'
            },
            {
              running: [
                'images/enemy-2-1.png',
                'images/enemy-2-2.png'
              ],
              dead: 'images/enemy-2-dead.png'
            },
            {
              running: [
                'images/enemy-3-1.png',
                'images/enemy-3-2.png'
              ],
              dead: 'images/enemy-3-dead.png'
            }
          ]
        },
        config: {
          fps: score => Math.min(60, 25 + Math.floor(score / 5)),              //帧率
          protagonist: {        //主角配置
            run: {              //奔跑配置
              start: 100,       //开始位置
              speed: 4          //奔跑速度(可以接受方法作为参数,根据当前的得分和已用时长跳转速度,(score:number,time:number)=>number)
            },
            jump: {             //跳跃配置
              power: 8,         //跳跃力度(px/f)
              gravity: 0.4,     //重力加速度(px/f²)
              count: 1          //弹跳次数(可支持多段跳)
            },
            dead: {
              power: 2          //死亡弹跳效果
            }
          },
          awards: [             //奖品配置
            {
              score: 1          //奖品获得的积分配置
            }
          ],
          flags: [
            {
              probability: 0.1         //随机出现,概率
            },
            {
              probability: 0.1         //随机出现,概率
            },
            {
              location: 300     //固定位置出现(可以接受方法作为参数,方法返回是否出现,(startLocation:number,endLocation:number)=>boolean)
            },
            {
              probability: 0.05,
              speed: 1,
              float: true,
            },
            {
              probability: 0.005,
              speed: 2,
              float: true,
            },
            {
              probability: 0.05,
              speed: 1,
              float: true
            }
          ],
          tiles: {
            empty: {
              min: score => Math.min(3, 1 + Math.floor(score / 25)),     //悬崖最小的大小
              max: score => Math.min(4, 2 + Math.floor(score / 20))      //悬崖最大的大小
            },
            land: {
              min: 1,     //陆地最小大小,不含左右地块,只计算中间地块
              max: score => Math.max(15, 100 - Math.floor(score / 25))     //陆地最大大小,不含左右地块,只计算中间地块
            }
          },
          win: {                //胜利条件
            time: Infinity,     //到达指定时间获胜
            score: Infinity     //获得指定积分获胜
          },
          background: {
            speed: 2           //背景卷动的速度
          },
          enemies: [
            {
              probability: 0.04,
              speed: 1,
              jump: 0,        //是否可以跳跃(飞天),为0表示不跳跃
              rebound: 1.5      //反弹力度
            },
            {
              probability: 0.02,
              speed: 1,
              jump: 0,
              rebound: 1.5,      //反弹力度
              hold: true        //死亡后是否保留尸体
            },
            {
              probability: 0.01,
              speed: 1,
              jump: 3,
              gravity: 0.05,
              rebound: 1.5,
              hold: true
            }
          ]
        }
      });
      parkour.onInited = function() {
        
      }
      parkour.onScoreChange = function(score, max) {
        document.getElementById('score').innerHTML = score;
      }
      parkour.onWin = function() {
        inputing = true;
        $.prompt('恭喜你获胜', {
          submit: function() {
            inputing = false;
            saveScore(parkour.score, function() {
              initParkour();
            });
          }
        })
      }
      parkour.onLose = function() {
        inputing = true;
        $.prompt('游戏结束', {
          submit: function() {
            inputing = false;
            saveScore(parkour.score, function() {
              initParkour();
            });
          }
        });
      }
    }

    window.onload = function() {
      initParkour();
      document.body.ontouchstart = document.body.onmousedown = function(e) {
        if (parkour.isPlaying()) {
          parkour.startJump();
        }
        if (!inputing) {
          e.preventDefault();
        }
      }
      document.body.ontouchend = document.body.onmouseup = function(e) {
        if (parkour.isInited()) {
          if (document.documentElement.scrollTop < 200 && !inputing) {
            parkour.start();
          }
        } else if (parkour.isPlaying()) {
          parkour.stopJump();
        }
        if (!inputing) {
          e.preventDefault();
        }
      }
      document.οncοntextmenu = function(e) {
        e.preventDefault();
      };
      refresh();
    }
  </script>
</head>
<body onselect="return false" onselectstart="return false" style="user-select: none;">
  <div style="width: 400px; margin: 0 auto;">
    <div style="position: absolute; z-index: 99; color: #fff; padding: 5px; vertical-align: middle;"><img src="images/award-1.png" alt="" style="vertical-align: middle;"><span style="vertical-align: middle;"> × </span><span id="score" style="vertical-align: middle;">0</span></div>
    <div id="parkour" style="pointer-events:none;">
      <img src="images/icon.png" alt="一款超级玛丽的跑酷游戏" style="position: absolute; left: -100px;">
    </div>
    <div style="text-align: center; font-size: 1.5em; font-weight: bold; padding: 8px; border-bottom: 1px solid #666;">排行榜</div>
    <div id="rank" class="rank"></div>
  </div>
</body>
</html>